package lambda;

// lambda表达式

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.function.BiConsumer;
import java.util.function.Consumer;

// 以下都是函数式接口：
//无返回值无参数
@FunctionalInterface
interface NoParameterNoReturn {
    void test();
}
//无返回值一个参数
@FunctionalInterface
interface OneParameterNoReturn {
    void test(int a);
}
//无返回值多个参数
@FunctionalInterface
interface MoreParameterNoReturn {
    void test(int a,int b);
}
//有返回值无参数
@FunctionalInterface
interface NoParameterReturn {
    int test();
}
//有返回值一个参数
@FunctionalInterface
interface OneParameterReturn {
    int test(int a);
}
//有返回值多参数
@FunctionalInterface
interface MoreParameterReturn {
    int test(int a,int b);
}




class Demo {
    void func() {
        System.out.println("Func()");
    }
}


public class Test {

    // Lambda在集合中的使用

    //Map
    public static void main(String[] args) {
        HashMap<Integer, String> map = new HashMap<>();
        map.put(1, "hello");
        map.put(2, "Kkk");
        map.put(3, "hello");
        map.put(4, "lambda");
        /*map.forEach(new BiConsumer<Integer, String>(){
            @Override
            public void accept(Integer k, String v){
                System.out.println("key:"+k+" " +"val:"+v);
            }
        });*/

        // Lambda重写：
        map.forEach((k,v) -> System.out.println("key:"+k+" " +"val:"+v));
    }

    // Collection接口  + List接口
    public static void main9(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("Hello");
        list.add("Zio.");
        list.add("hello");
        list.add("lambda");

        /*// 使用forEach方法进行打印
        list.forEach(new Consumer<String>() {
            // 其实就是通过重写accept方法来实现的。
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        });*/

        // 看forEach其实就是：传入一个s，输出s  -->Lambda表达式
        list.forEach(s -> System.out.println(s));
        System.out.println("===");

        // 比较大小List接口
        /*list.sort(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.compareTo(o2); // String是引用对象
            }
        });*/

        // 同样进行改写：
        list.sort((o1,o2) -> o1.compareTo(o2));
        list.forEach(s -> System.out.println(s));

        list.sort((str1,str2)-> str1.length()-str2.length());
        System.out.println(list);

    }


    // Lambda表达式
    public static void main8(String[] args) {
        int size = 12;
        ///size = 8;
        MoreParameterNoReturn moreParameterNoReturn = (int a, int b) -> {
            System.out.println(a+b);
            //size = 9;
            System.out.println(size); // 在Lambda表达式中同样不能进行修改！

            int len = 2;
            len = 6; // 这样子的修改是ok的！
            System.out.println(len);
        };
        moreParameterNoReturn.test(12,18);
        System.out.println("------");

    }


    // 匿名内部类
    public static void main7(String[] args) {
        new Demo().func(); // 匿名对象

        int a = 28; // 定义在内部类之外
        //a = 882; // 在这里修改也是错误的！
        new Demo() {
            @Override
            void func() {
                // 在这里进行修改a的值会报错
                // reason：在匿名内部类中使用的外部变量一定是之前（也就是进入内部类之前后）没有被修改过的量！！！
                //a = 82;

                // 内部类中定义的变量可以进行修改
                int c = 99;
                c=88;
                System.out.println(c);

                //super.func();
                System.out.println("重写该方法！"+a);
            }
        }.func();
        // 匿名内部类：注意进行区分--> 重写方法
        // 如何调用匿名内部类 .方法
    }

    // 将以上6个方法改为Lambda表达式
    // 相当于重写抽象方法

    // 有返回值就要进行接收

    // 有返回多参
    public static void main6(String[] args) {
        MoreParameterReturn moreParameterReturn = (x,y) -> x-y;
        System.out.println(moreParameterReturn.test(2,6));
    }

    // 有返回值一参
    public static void main5(String[] args) {
        OneParameterReturn oneParameterReturn = x -> 2*x; // 传参x 返回2x
        int ret = oneParameterReturn.test(8);
        System.out.println(ret);
    }


    // 有返回值无参
    public static void main4(String[] args) {
        NoParameterReturn noParameterReturn = () -> {return 2;};
        int ret = noParameterReturn.test();
        System.out.println(ret);
        System.out.println("------");

        // 化简版：省略return 、 {}
        System.out.println("化简版：");
        NoParameterReturn noParameterReturn1 = () ->  2;
        int ret1 = noParameterReturn1.test();
        System.out.println(ret1);
    }

    // 无返回值多参数
    public static void main3(String[] args) {
        MoreParameterNoReturn moreParameterNoReturn = (int a, int b) -> {
            System.out.println(a+b);
        };
        moreParameterNoReturn.test(12,18);
        System.out.println("------");

        // 两个参数类型同时省略，不省略括号
        MoreParameterNoReturn moreParameterNoReturn1 = (a, b) -> System.out.println(a+b);
        moreParameterNoReturn1.test(12,13);
        System.out.println("------");
    }

    // 无返回值一参
    public static void main2(String[] args) {
        OneParameterNoReturn oneParameterNoReturn = (int x) -> {
            System.out.println("测试！"+x);
        };
        oneParameterNoReturn.test(88);
        System.out.println("------");

        // 只有一个参数：可以不加类型、不加括号   只有一个语句：可以不加{}
        System.out.println("简化1:");
        OneParameterNoReturn oneParameterNoReturn1 = x -> System.out.println(x);
        oneParameterNoReturn1.test(68);

        //这种一般是方法引用
        System.out.println("简化2:"); // 鼠标+alt+回车
        OneParameterNoReturn oneParameterNoReturn2 = System.out::println;
        oneParameterNoReturn2.test(66);

    }

    // 无返回值无参
    public static void main1(String[] args) {

        // 接口引用具体实现类（其实是匿名内部类）来实现
        // 匿名内部类，实现了接口，重写了方法。
        NoParameterNoReturn noParameterNoReturn = new NoParameterNoReturn() {
            @Override
            public void test() {
                System.out.println("测试！");
            }
        };
        noParameterNoReturn.test();
        System.out.println("------");

        // 使用Lambda改写
        // （参数） -> 语句块{} 如果语句块中只有一条语句则可以直接省略{}
        NoParameterNoReturn noParameterNoReturn1 = () -> {
            System.out.println("测试Lambda1");
            System.out.println("再次测试Lambda1");
        };
        noParameterNoReturn1.test();
        System.out.println("------");

        NoParameterNoReturn noParameterNoReturn2 = () -> System.out.println("test1!");
        noParameterNoReturn2.test();

    }
}
